home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / backends / buffchan.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  11KB  |  540 lines

  1. /*  $Revision: 1.9 $
  2. **
  3. **  Buffered file exploder for innd.
  4. */
  5. #include "configdata.h"
  6. #include <stdio.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <signal.h>
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include "paths.h"
  13. #include "libinn.h"
  14. #include "clibrary.h"
  15. #include "qio.h"
  16. #include "macros.h"
  17.  
  18. extern void    MAPread();
  19. extern char    *MAPname();
  20.  
  21. /*
  22. **  Hash functions for hashing sitenames.
  23. */
  24. #define SITE_HASH(Name, p, j)    \
  25.     for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++
  26. #define SITE_SIZE    128
  27. #define SITE_BUCKET(j)    &SITEtable[j & (SITE_SIZE - 1)]
  28.  
  29.  
  30. /*
  31. **  Entry for a single active site.
  32. */
  33. typedef struct _SITE {
  34.     BOOL    Dropped;
  35.     STRING    Name;
  36.     int        CloseLines;
  37.     int        FlushLines;
  38.     time_t    LastFlushed;
  39.     time_t    LastClosed;
  40.     int     CloseSeconds;
  41.     int        FlushSeconds;
  42.     FILE    *F;
  43.     STRING    Filename;
  44.     char    *Buffer;
  45. } SITE;
  46.  
  47.  
  48. /*
  49. **  Site hashtable bucket.
  50. */
  51. typedef struct _SITEHASH {
  52.     int        Size;
  53.     int        Used;
  54.     SITE    *Sites;
  55. } SITEHASH;
  56.  
  57.  
  58. /* Global variables. */
  59. STATIC char    *Format;
  60. STATIC STRING    Map;
  61. STATIC int    BufferMode;
  62. STATIC int    CloseEvery;
  63. STATIC int    FlushEvery;
  64. STATIC int    CloseSeconds;
  65. STATIC int    FlushSeconds;
  66. STATIC SIGVAR    GotInterrupt;
  67. STATIC SITEHASH    SITEtable[SITE_SIZE];
  68. STATIC TIMEINFO    Now;
  69.  
  70.  
  71. #if    defined(DONT_HAVE_FCHMOD)
  72. /*
  73. **  A dummy fchmod.
  74. */
  75. /* ARGSUSED */
  76. int
  77. fchmod(i)
  78.     int        i;
  79. {
  80. }
  81. #endif    /* defined(DONT_HAVE_FCHMOD) */
  82.  
  83.  
  84. /*
  85. **  Set up the site information.  Basically creating empty buckets.
  86. */
  87. STATIC void
  88. SITEsetup()
  89. {
  90.     register SITEHASH    *shp;
  91.  
  92.     for (shp = SITEtable; shp < ENDOF(SITEtable); shp++) {
  93.     shp->Size = 3;
  94.     shp->Sites = NEW(SITE, shp->Size);
  95.     shp->Used = 0;
  96.     }
  97. }
  98.  
  99.  
  100. /*
  101. **  Close a site
  102. */
  103. STATIC void
  104. SITEclose(sp)
  105.     register SITE       *sp;
  106. {
  107.     register FILE    *F;
  108.  
  109.     if ((F = sp->F) != NULL) {
  110.     if (fflush(F) == EOF || ferror(F)
  111.      || fchmod((int)fileno(F), 0664) < 0
  112.      || fclose(F) == EOF)
  113.         (void)fprintf(stderr, "buffchan %s cant close %s, %s\n",
  114.             sp->Name, sp->Filename, strerror(errno));
  115.     sp->F = NULL;
  116.     }
  117. }
  118.  
  119. /*
  120. **  Close all open sites.
  121. */
  122. STATIC void
  123. SITEcloseall()
  124. {
  125.     register SITEHASH    *shp;
  126.     register SITE    *sp;
  127.     register int    i;
  128.  
  129.     for (shp = SITEtable; shp < ENDOF(SITEtable); shp++)
  130.     for (sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
  131.         SITEclose(sp);
  132. }
  133.  
  134.  
  135. /*
  136. **  Open the file for a site.
  137. */
  138. STATIC void
  139. SITEopen(sp)
  140.     register SITE    *sp;
  141. {
  142.     int            e;
  143.  
  144.     if ((sp->F = xfopena(sp->Filename)) == NULL
  145.      && ((e = errno) != EACCES || chmod(sp->Filename, 0644) < 0
  146.       || (sp->F = xfopena(sp->Filename)) == NULL)) {
  147.     (void)fprintf(stderr, "buffchan %s cant fopen %s, %s\n",
  148.         sp->Name, sp->Filename, strerror(e));
  149.     if ((sp->F = fopen("/dev/null", "w")) == NULL) {
  150.         /* This really should not happen. */
  151.         (void)fprintf(stderr, "buffchan %s cant fopen %s, %s\n",
  152.             sp->Name, "/dev/null", strerror(errno));
  153.         exit(1);
  154.     }
  155.     }
  156.     else if (fchmod((int)fileno(sp->F), 0444) < 0)
  157.     (void)fprintf(stderr, "buffchan %s cant fchmod %s %s\n",
  158.         sp->Name, sp->Filename, strerror(errno));
  159.     
  160.     if (BufferMode != '\0')
  161.     setbuf(sp->F, sp->Buffer);
  162.  
  163.     /* Reset all counters. */
  164.     sp->FlushLines = 0;
  165.     sp->CloseLines = 0;
  166.     sp->LastFlushed = Now.time;
  167.     sp->LastClosed = Now.time;
  168.     sp->Dropped = FALSE;
  169. }
  170.  
  171.  
  172. /*
  173. **  Find a site, possibly create if not found.
  174. */
  175. STATIC SITE *
  176. SITEfind(Name, CanCreate)
  177.     char        *Name;
  178.     BOOL        CanCreate;
  179. {
  180.     register char    *p;
  181.     register int    i;
  182.     unsigned int    j;
  183.     register SITE    *sp;
  184.     SITEHASH        *shp;
  185.     char        c;
  186.     char        buff[BUFSIZ];
  187.  
  188.     /* Look for site in the hash table. */
  189.     /* SUPPRESS 6 *//* Over/underflow from plus expression */
  190.     SITE_HASH(Name, p, j);
  191.     shp = SITE_BUCKET(j);
  192.     for (c = *Name, sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
  193.     if (c == sp->Name[0] && caseEQ(Name, sp->Name))
  194.         return sp;
  195.     if (!CanCreate)
  196.     return NULL;
  197.  
  198.     /* Adding a new site -- grow hash bucket if we need to. */
  199.     if (shp->Used == shp->Size - 1) {
  200.     shp->Size *= 2;
  201.     RENEW(shp->Sites, SITE, shp->Size);
  202.     }
  203.     sp = &shp->Sites[shp->Used++];
  204.  
  205.     /* Fill in the structure for the new site. */
  206.     sp->Name = COPY(Name);
  207.     (void)sprintf(buff, (STRING)Format, Map ? MAPname(Name) : sp->Name);
  208.     sp->Filename = COPY(buff);
  209.     if (BufferMode == 'u')
  210.     sp->Buffer = NULL;
  211.     else if (BufferMode == 'b')
  212.     sp->Buffer = NEW(char, BUFSIZ);
  213.     SITEopen(sp);
  214.  
  215.     return sp;
  216. }
  217.  
  218.  
  219. /*
  220. **  Flush a site -- close and re-open the file.
  221. */
  222. STATIC void
  223. SITEflush(sp)
  224.     register SITE    *sp;
  225. {
  226.     register FILE    *F;
  227.  
  228.     if ((F = sp->F) != NULL) {
  229.     if (fflush(F) == EOF || ferror(F)
  230.      || fchmod((int)fileno(F), 0664) < 0
  231.      || fclose(F) == EOF)
  232.         (void)fprintf(stderr, "buffchan %s cant close %s, %s\n",
  233.             sp->Name, sp->Filename, strerror(errno));
  234.     sp->F = NULL;
  235.     }
  236.     if (!sp->Dropped)
  237.     SITEopen(sp);
  238. }
  239.  
  240.  
  241. /*
  242. **  Flush all open sites.
  243. */
  244. STATIC void
  245. SITEflushall()
  246. {
  247.     register SITEHASH    *shp;
  248.     register SITE    *sp;
  249.     register int    i;
  250.  
  251.     for (shp = SITEtable; shp < ENDOF(SITEtable); shp++)
  252.     for (sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
  253.         SITEflush(sp);
  254. }
  255.  
  256.  
  257. /*
  258. **  Write data to a site.
  259. */
  260. STATIC void
  261. SITEwrite(name, text, len)
  262.     register char    *name;
  263.     register char    *text;
  264.     register int    len;
  265. {
  266.     register SITE    *sp;
  267.  
  268.     sp = SITEfind(name, TRUE);
  269.     if (sp->F == NULL)
  270.     SITEopen(sp);
  271.  
  272.     if (fwrite((POINTER)text, (SIZE_T)1, (SIZE_T)len, sp->F) != len)
  273.     (void)fprintf(stderr, "buffchan %s cant write %s\n",
  274.         sp->Name, strerror(errno));
  275.  
  276.     /* Bump line count; see if time to close or flush. */
  277.     if (CloseEvery && ++(sp->CloseLines) >= CloseEvery) {
  278.     SITEflush(sp);
  279.     return;
  280.     }
  281.     if (CloseSeconds && sp->LastClosed + CloseSeconds < Now.time) {
  282.     SITEflush(sp);
  283.     return;
  284.     }
  285.     if (FlushEvery && ++(sp->FlushLines) >= FlushEvery) {
  286.     if (fflush(sp->F) == EOF || ferror(sp->F))
  287.         (void)fprintf(stderr, "buffchan %s cant flush %s, %s\n",
  288.             sp->Name, sp->Filename, strerror(errno));
  289.     sp->LastFlushed = Now.time;
  290.     sp->FlushLines = 0;
  291.     }
  292.     else if (FlushSeconds && sp->LastFlushed + FlushSeconds < Now.time) {
  293.     if (fflush(sp->F) == EOF || ferror(sp->F))
  294.         (void)fprintf(stderr, "buffchan %s cant flush %s, %s\n",
  295.             sp->Name, sp->Filename, strerror(errno));
  296.     sp->LastFlushed = Now.time;
  297.     sp->FlushLines = 0;
  298.     }
  299. }
  300.  
  301.  
  302. /*
  303. **  Handle a command message.
  304. */
  305. STATIC void
  306. Process(p)
  307.     register char    *p;
  308. {
  309.     register SITE    *sp;
  310.  
  311.     if (*p == 'b' && EQn(p, "begin", 5))
  312.     /* No-op. */
  313.     return;
  314.  
  315.     if (*p == 'f' && EQn(p, "flush", 5)) {
  316.     for (p += 5; ISWHITE(*p); p++)
  317.         continue;
  318.     if (*p == '\0')
  319.         SITEflushall();
  320.     else if ((sp = SITEfind(p, FALSE)) != NULL)
  321.         SITEflush(sp);
  322.     else
  323.         /*(void)fprintf(stderr, "buffchan flush %s unknown site\n", p);*/
  324.         ;
  325.     return;
  326.     }
  327.  
  328.     if (*p == 'd' && EQn(p, "drop", 4)) {
  329.     for (p += 4; ISWHITE(*p); p++)
  330.         continue;
  331.     if (*p == '\0')
  332.         SITEcloseall();
  333.     else if ((sp = SITEfind(p, FALSE)) == NULL)
  334.         (void)fprintf(stderr, "buffchan drop %s unknown site\n", p);
  335.     else {
  336.         SITEclose(sp);
  337.         sp->Dropped = TRUE;
  338.     }
  339.     return;
  340.     }
  341.  
  342.     if (*p == 'r' && EQn(p, "readmap", 7)) {
  343.     MAPread(Map);
  344.     return;
  345.     }
  346.  
  347.     /* Other command messages -- ignored. */
  348.     (void)fprintf(stderr, "buffchan unknown message %s\n", p);
  349. }
  350.  
  351.  
  352. /*
  353. **  Print usage message and exit.
  354. */
  355. STATIC NORETURN
  356. Usage()
  357. {
  358.     (void)fprintf(stderr, "Usage error.\n");
  359.     exit(1);
  360. }
  361.  
  362.  
  363. /*
  364. **  Mark that we got a signal; let two signals kill us.
  365. */
  366. STATIC SIGHANDLER
  367. CATCHinterrupt(s)
  368.     int        s;
  369. {
  370.     GotInterrupt = TRUE;
  371.     (void)signal(s, SIG_DFL);
  372. }
  373.  
  374.  
  375. int
  376. main(ac, av)
  377.     int            ac;
  378.     char        *av[];
  379. {
  380.     static char        BATCHDIR[] = _PATH_BATCHDIR;
  381.     register QIOSTATE    *qp;
  382.     register int    i;
  383.     register int    Fields;
  384.     register char    *p;
  385.     register char    *next;
  386.     register char    *line;
  387.     char        *Directory;
  388.     BOOL        Redirect;
  389.     FILE        *F;
  390.  
  391.     /* Set defaults. */
  392.     Directory = NULL;
  393.     Fields = 1;
  394.     Format = NULL;
  395.     Redirect = TRUE;
  396.     GotInterrupt = FALSE;
  397.     (void)umask(NEWSUMASK);
  398.  
  399.     (void)signal(SIGHUP, CATCHinterrupt);
  400.     (void)signal(SIGINT, CATCHinterrupt);
  401.     (void)signal(SIGQUIT, CATCHinterrupt);
  402.     (void)signal(SIGPIPE, CATCHinterrupt);
  403.     (void)signal(SIGTERM, CATCHinterrupt);
  404.     (void)signal(SIGALRM, CATCHinterrupt);
  405.  
  406.     /* Parse JCL. */
  407.     while ((i = getopt(ac, av, "bc:C:d:f:l:L:m:p:rs:u")) != EOF)
  408.     switch (i) {
  409.     default:
  410.         Usage();
  411.         /* NOTREACHED */
  412.     case 'b':
  413.     case 'u':
  414.         BufferMode = i;
  415.         break;
  416.     case 'c':
  417.         CloseEvery = atoi(optarg);
  418.         break;
  419.     case 'C':
  420.         CloseSeconds = atoi(optarg);
  421.         break;
  422.     case 'd':
  423.         Directory = optarg;
  424.         if (Format == NULL)
  425.         Format ="%s";
  426.         break;
  427.     case 'f':
  428.         Fields = atoi(optarg);
  429.         break;
  430.     case 'l':
  431.         FlushEvery = atoi(optarg);
  432.         break;
  433.     case 'L':
  434.         FlushSeconds = atoi(optarg);
  435.         break;
  436.     case 'm':
  437.         Map = optarg;
  438.         MAPread(Map);
  439.         break;
  440.     case 'p':
  441.         if ((F = fopen(optarg, "w")) == NULL) {
  442.         (void)fprintf(stderr, "buffchan cant fopen %s %s\n",
  443.             optarg, strerror(errno));
  444.         exit(1);
  445.         }
  446.         (void)fprintf(F, "%ld\n", (long)getpid());
  447.         if (ferror(F) || fclose(F) == EOF) {
  448.         (void)fprintf(stderr, "buffchan cant fclose %s %s\n",
  449.             optarg, strerror(errno));
  450.         exit(1);
  451.         }
  452.         break;
  453.     case 'r':
  454.         Redirect = FALSE;
  455.         break;
  456.     case 's':
  457.         Format = optarg;
  458.         break;
  459.     }
  460.     ac -= optind;
  461.     av += optind;
  462.     if (ac)
  463.     Usage();
  464.  
  465.     /* Do some basic set-ups. */
  466.     if (Redirect)
  467.     (void)freopen(_PATH_ERRLOG, "a", stderr);
  468.     if (Format == NULL) {
  469.     Format = NEW(char, STRLEN(BATCHDIR) + 1 + 2 + 1);
  470.     (void)sprintf(Format, "%s/%%s", BATCHDIR);
  471.     }
  472.     if (Directory && chdir(Directory) < 0) {
  473.     (void)fprintf(stderr, "buffchan cant chdir %s %s\n",
  474.         Directory, strerror(errno));
  475.     exit(1);
  476.     }
  477.     SITEsetup();
  478.  
  479.     /* Read input. */
  480.     for (qp = QIOfdopen((int)fileno(stdin), 0); !GotInterrupt ; ) {
  481.     if ((line = QIOread(qp)) == NULL) {
  482.         if (QIOerror(qp)) {
  483.         (void)fprintf(stderr, "buffchan cant read %s\n",
  484.             strerror(errno));
  485.         break;
  486.         }
  487.         if (QIOtoolong(qp)) {
  488.         (void)fprintf(stderr, "buffchan long_line");
  489.         (void)QIOread(qp);
  490.         continue;
  491.         }
  492.  
  493.         /* Normal EOF. */
  494.         break;
  495.     }
  496.  
  497.     /* Command? */
  498.     if (*line == EXP_CONTROL && *++line != EXP_CONTROL) {
  499.         Process(line);
  500.         continue;
  501.     }
  502.  
  503.     /* Skip the right number of leading fields. */
  504.     for (i = Fields, p = line; *p; p++)
  505.         if (*p == ' ' && --i <= 0)
  506.         break;
  507.     if (*p == '\0')
  508.         /* Nothing to write.  Probably shouldn't happen. */
  509.         continue;
  510.  
  511.     /* Add a newline, get the length of all leading fields. */
  512.     *p++ = '\n';
  513.     i = p - line;
  514.  
  515.     if (GetTimeInfo(&Now) < 0) {
  516.         (void)fprintf(stderr, "buffchan cant gettime %s\n",
  517.             strerror(errno));
  518.         break;
  519.     }
  520.  
  521.     /* Rest of the line is space-separated list of filenames. */
  522.     for (; *p; p = next) {
  523.         /* Skip whitespace, get next word. */
  524.         while (*p == ' ')
  525.         p++;
  526.         for (next = p; *next && *next != ' '; next++)
  527.         continue;
  528.         if (*next)
  529.         *next++ = '\0';
  530.  
  531.         SITEwrite(p, line, i);
  532.     }
  533.  
  534.     }
  535.  
  536.     SITEcloseall();
  537.     exit(0);
  538.     /* NOTREACHED */
  539. }
  540.